defmodule CentralControl do
  @moduledoc """
  Documentation for CentralControl.
  """

  alias CentralControl.OwnerAdapter
  alias CentralControl.ManagerAdapter
  alias CentralControl.PartInAdapter
  alias CentralControl.Repo

  alias MessageServer.MessageContentAdapter
  alias MessageServer.MessageAdapter

  alias Club.ActivityAdapter
  alias Club.FinancialAdapter
  alias Club.VoteAdapter
  @doc """
  {:ok, _} 成功
  {:error, changeset} 错误
  """
  def user_create_club(params) do
    userid = Map.get(params, :userid)
    #利用事务解决一些错误恢复问题
    Repo.transaction(fn -> 
          club = Club.Adapter.create_club(params)
          ownerParams = %{userid: userid, clubid: club.id}
          OwnerAdapter.create_owner(ownerParams)
          ManagerAdapter.create_manager(ownerParams)
          PartInAdapter.partin(Map.put(ownerParams, :duty, "创建者/初代目"))

          %{clubid: club.id, invitecode: club.invitecode}
          end)
    end

    def user_delete_club(params) do
      userid = Map.get(params, :userid)
      Repo.transaction(fn -> 
                club = Club.Adapter.find_club(Map.get(params, :invitecode))
                owner = OwnerAdapter.findOwner(club.id)
                if (owner != nil) && (owner.userid == userid) do
                  OwnerAdapter.deleteclub(club.id)
                  ManagerAdapter.deleteclub(club.id)
                  PartInAdapter.deleteclub(club.id)
                end
          end)
    end

  @doc """
    {:ok, partin} 成功
    {:ok, nil} 查无此人或者已经是成员之一
    {:error, changset} 出错
    还要出现异常，这个尚不明确
    """
  def user_partin_club(params) do
      # invitecode = Map.get(params, :invitecode)
      # case Club.Adapter.find_club(invitecode) do
      #   nil ->
      #     {:error, "not found club"}
      #   club ->

      # end
      Repo.transaction(fn -> 
                club = Club.Adapter.find_club(Map.get(params, :invitecode))
                if PartInAdapter.inclub(Map.get(params, :userid), club.id) == nil do
                      PartInAdapter.partin(Map.put(params, :clubid, club.id))
                end
          end)
    end

    @doc """
    {:ok, manager} 成功
    {:ok, nil} 查无此人或者已经是管理员
    {:error, changset} 出错
    还要出现异常，这个尚不明确
    """
    def user_manager_club(params) do
      userid = Map.get(params, :userid)
      Repo.transaction(fn ->
                club = Club.Adapter.find_club(Map.get(params, :invitecode))
                if (PartInAdapter.inclub(userid, club.id) != nil)  && (ManagerAdapter.isManager(userid, club.id) == nil) do
                      ManagerAdapter.create_manager(params)
                end
          end)
    end

    def user_quit_club(userid, clubid) do
      PartInAdapter.quit(userid, clubid)
    end

    def show_user_club(userid) do
      case PartInAdapter.clublist(userid) do
        [] ->
          {:ok, %{"clublist" => nil}}
        list ->
          clublist = for partin <- list, into: %{} do
                        club = Club.Adapter.find_club(partin.clubid)
                        {club.invitecode, club.name}
                      end
          {:ok, %{"clublist" => clublist}}
      end
    end

    def show_own_club(userid) do
      OwnerAdapter.clublist(userid)
    end

    def show_club_manager(invitecode) do
      Repo.transaction(fn ->
                        club = Club.Adapter.find_club(invitecode)
                        ManagerAdapter.listManager(club.id)
                        end)
    end



    def show_club_member(invitecode) do
        club = Club.Adapter.find_club(invitecode)
        list = PartInAdapter.memberlist(club.id)

        memberlist = Enum.map(list,
                    fn member ->
                        member.userid
                      end)
        {:ok, %{memberlist: memberlist} }
    end

    def show_user_in_club(userid, invitecode) do
        case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case PartInAdapter.inclub(userid, club.id) do
              nil ->
                {:error, "not in club"}
              partin ->
                {:ok, dt} = partin.inserted_at |> DateTime.from_naive("Etc/UTC")
                ii = DateTime.to_unix dt

                params = %{"partintime" => ii, "duty" => partin.duty}

                name = Map.get(club, :name)
                introduction = Map.get(club, :introduction)
                icon = Map.get(club, :icon)
                school = Map.get(club, :school)

                params = params
                          |> Map.put(:name, name)
                          |> Map.put(:introduction, introduction)
                          |> Map.put(:icon, icon)
                          |> Map.put(:school, school)
                owner = OwnerAdapter.findOwner(club.id)
                manager = ManagerAdapter.isManager(userid, club.id)
                params = params 
                          |> Map.put("isOwner", Map.get(owner, :userid) == userid) 
                          |> Map.put("isManager", manager != nil)
                {:ok, params}
            end
        end
    end

    def requestPartin(params) do
      userid = params.userid
      username = params.username
      invitecode = params.invitecode
      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case PartInAdapter.inclub(userid, club.id) do
              nil ->
                Repo.transaction(fn ->
                        msgcontent = %{}
                                  |> Map.put(:content, username <>" want to particpate in club " <> club.name)
                                  |> MessageContentAdapter.create_message_content

                        msg = %{type: 1, srcid: userid, destid: club.id}
                                |> MessageAdapter.create_msg(msgcontent.id)
                        {:ok, managerlist} = show_club_manager(invitecode)
                        manageridlist = for manager <- managerlist, do: manager.userid

                        %{type: 2, srcid: club.id} |> MessageAdapter.broadcast(manageridlist, msg.id)

                        %{msg: "operate successfully"}
                        end)
              partin ->
                {:error, "arleady part in club"}
            end
        end
    end

    def allowPartIn(params) do
      opid = params.opid
      userid = params.userid
      invitecode = params.invitecode

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            if ManagerAdapter.isManager(userid, club.id) == nil do
              {:error, "permit denied"}
            else
              case PartInAdapter.inclub(opid, club.id) do
                nil ->
                  {:ok, partin} = %{userid: opid, clubid: club.id} |> PartInAdapter.partin
                  {:ok, %{msg: "operate successfully"} }
                partin ->
                  {:error, "arleady part in club"}
                end
            end
      end
    end

    def createActivity(params) do
      userid = params.userid
      invitecode = params.invitecode

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            if ManagerAdapter.isManager(userid, club.id) == nil do
              {:error, "permit denied"}
            else
              params = Map.put(params, :clubid, club.id)
              case ActivityAdapter.create(params) do
                nil ->
                  {:error, "sth wrong!"}
                activity ->
                  {:ok, %{activityid: activity.id}}
              end
            end
      end
    end

    def createVote(params) do
      userid = params.userid
      invitecode = params.invitecode

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            if ManagerAdapter.isManager(userid, club.id) == nil do
              {:error, "permit denied"}
            else
              {:ok, content} = Poison.encode(params.content)
              params = params |> Map.put(:clubid, club.id) |> Map.put(:content, content)
              case VoteAdapter.create(params) do
                nil ->
                  {:error, "sth wrong!"}
                vote ->
                  {:ok, %{voteid: vote.id} }
              end
            end
      end
    end

    def createVoteChoice(params) do
      userid = params.userid
      invitecode = params.invitecode
      voteid = params.voteid

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case PartInAdapter.inclub(userid, club.id) do
                nil ->
                  {:error, "permit denied"}
                partin ->
                  if VoteAdapter.has_choice?(userid, voteid) == nil do
                    {:ok, choice} = Poison.encode(params.choice)
                    params = params |> Map.put(:choice, choice)
                    case VoteAdapter.create_vote_choice(params) do
                      nil ->
                        {:error, "sth wrong"}
                      choice ->
                        {:ok, %{choiceid: choice.id}}
                    end
                  else
                    {:error, "has choice"}
                  end
                end
      end
    end

    def showVoteList(params) do
      userid = params.userid
      invitecode = params.invitecode

      case isPartIn(userid, invitecode) do
        {:error, msg} ->
          {:error, msg}
        {:ok, partin} ->
          list = VoteAdapter.get_club_vote(partin.clubid)
          votelist = Enum.map(list,
                      fn vote ->
                        {:ok, dt} = vote.inserted_at |> DateTime.from_naive("Etc/UTC")
                         ct = DateTime.to_unix dt
                        %{id: vote.id, theme: vote.theme, createtime: ct, type: vote.type}
                      end)
          {:ok, %{votelist: votelist} }
      end
    end

    def showVoteDetail(params) do
      userid = params.userid
      invitecode = params.invitecode

      case isPartIn(userid, invitecode) do
        {:error, msg} ->
          {:error, msg}
        {:ok, partin} ->
          vote = VoteAdapter.get_info_vote(params.voteid)
          if vote.clubid != partin.clubid do
            {:error, "permit deny"}
          else
            {:ok, dt} = vote.inserted_at |> DateTime.from_naive("Etc/UTC")
            ct = DateTime.to_unix dt
            chosen = VoteAdapter.has_choice?(userid, vote.id)
            {:ok, content} = Poison.decode(vote.content)
            detail = %{id: vote.id, theme: vote.theme, type: vote.type, content: content, createtime: ct}
                      |> Map.put(:haschoice, chosen != nil)
            
            {:ok, %{detail: detail} }
          end
      end
    end

    def showVoteResult(params) do
      userid = params.userid
      invitecode = params.invitecode

      case isPartIn(userid, invitecode) do
        {:error, msg} ->
          {:error, msg}
        {:ok, partin} ->
          vote = VoteAdapter.get_info_vote(params.voteid)
          if vote.clubid != partin.clubid do
            {:error, "permit deny"}
          else
            VoteAdapter.count_vote(vote.id)
          end
      end

    end

    def createFinancial(params) do
      userid = params.userid
      invitecode = params.invitecode

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            if PartInAdapter.inclub(userid, club.id) == nil do
              {:error, "permit denied"}
            else
              params = Map.put(params, :clubid, club.id)
              params = Map.put(params, :reportid, userid)
              case FinancialAdapter.create(params) do
                nil ->
                  {:error, "sth wrong!"}
                financial ->
                  {:ok, %{financial: financial.id}}
              end
            end
      end
    end

    def showClubFinancialList(params) do
      userid = params.userid
      invitecode = params.invitecode

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            if ManagerAdapter.isManager(userid, club.id) == nil do
              {:error, "permit denied"}
            else
              finList = FinancialAdapter.get_club_financial(club.id)
              list = Enum.map(finList,
                        fn financial ->
                            {:ok, dt} = financial.inserted_at |> DateTime.from_naive("Etc/UTC")
                            ct = DateTime.to_unix dt
                            %{financialid: financial.id, createtime: ct, type: financial.type, status: financial.status}
                            end)
              {:ok, %{financiallist: list} }
            end
      end
    end

    def showFinancialDetail(params) do
      userid = params.userid
      invitecode = params.invitecode
      financialid = params.financialid

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            if ManagerAdapter.isManager(userid, club.id) == nil do
              {:error, "permit denied"}
            else
              case FinancialAdapter.get_info_financial(financialid) do
                nil ->
                  {:error, "not exist!"}
                financial ->
                  if financial.clubid == club.id do
                    {:ok, dt} = financial.inserted_at |> DateTime.from_naive("Etc/UTC")
                    ct = DateTime.to_unix dt

                    {:ok, dt} = financial.updated_at |> DateTime.from_naive("Etc/UTC")
                    ut = DateTime.to_unix dt

                    res = %{
                        type: financial.type,
                        amount: financial.amount,
                        reportid: financial.reportid,
                        acceptorid: Map.get(financial, :acceptorid),
                        comment: Map.get(financial, :comment),
                        src: Map.get(financial, :src),
                        activity: Map.get(financial, :activity),
                        use: Map.get(financial, :use),
                        status: financial.status,
                        createtime: ct,
                        updatetime: ut
                    }

                    {:ok, %{detail: res} }
                  else
                    {:error, "permit denied"}
                  end
              end
            end
      end
    end

    def updateFinancial(params) do
      userid = params.userid
      invitecode = params.invitecode
      financialid = params.financialid

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            if ManagerAdapter.isManager(userid, club.id) == nil do
              {:error, "permit denied"}
            else
              case FinancialAdapter.get_info_financial(financialid) do
                nil ->
                  {:error, "not exist!"}
                financial ->
                  cond do
                    financial.status != 0 ->
                      {:error, "already handle"}
                    financial.clubid != club.id ->
                      {:error, "permit denied"}
                    financial.clubid == club.id ->
                      {:ok, _} = FinancialAdapter.update_financial(financial.id, %{status: params.status, acceptorid: userid})
                      {:ok, %{financialid: financial.id} }
                  end
              end
            end
      end
    end

    def showActivityList(params) do
      userid = params.userid
      invitecode = params.invitecode

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case PartInAdapter.inclub(userid, club.id) do
                nil ->
                  {:error, "permit denied"}
                partin ->
                  activitylist = ActivityAdapter.get_club_activity(club.id)
                  list = Enum.map(activitylist,
                     fn activity -> 
                         {:ok, dt} = activity.inserted_at |> DateTime.from_naive("Etc/UTC")
                         ct = DateTime.to_unix dt
                         %{createtime: ct, title: activity.title, activityid: activity.id}
                         end)
                  {:ok, %{activitylist: list} }
                end
      end
    end

    def showActivityDetail(params) do
      userid = params.userid
      invitecode = params.invitecode
      activityid = params.activityid

      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case PartInAdapter.inclub(userid, club.id) do
                nil ->
                  {:error, "permit denied"}
                partin ->
                  activity = ActivityAdapter.get_info_activity(activityid)
                  {:ok, dt} = activity.inserted_at |> DateTime.from_naive("Etc/UTC")
                         ct = DateTime.to_unix dt
                  {:ok, dt} = activity.starttime |> DateTime.from_naive("Etc/UTC")
                         st = DateTime.to_unix dt
                  {:ok, dt} = activity.endtime |> DateTime.from_naive("Etc/UTC")
                         et = DateTime.to_unix dt
                  res = %{id: activity.id, title: activity.title, createtime: ct, starttime: st, endtime: et, 
                          place: activity.place, cotent: activity.content, attachmentid: activity.attachmentid }

                  {:ok, %{activity: res} }
                end
      end
    end

    def show_user_unread_msg(params) do
      userid = params.userid
      invitecode = params.invitecode
      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case PartInAdapter.inclub(userid, club.id) do
              nil ->
                {:error, "not in club"}
               partin ->
                MessageAdapter.find_user_unread_msg(club.id, userid)
            end
      end
    end

    def show_msg(params) do
      userid = params.userid
      msgid = params.msgid

      case MessageAdapter.find_msg(msgid) do
        nil ->
          {:error, "not such msg id"}
        msg ->
          if msg.destid == userid do
            MessageAdapter.find_user_msg(msgid)
          else
            {:error, "not your msg"}
          end
      end
    end

    defp isPartIn(userid, invitecode) do
      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case PartInAdapter.inclub(userid, club.id) do
                nil ->
                  {:error, "permit denied"}
                partin ->
                  {:ok, partin}
            end
      end
    end

    defp isManager(userid, invitecode) do
      case Club.Adapter.find_club(invitecode) do
          nil ->
            {:error, "not exist!"}
          club ->
            case ManagerAdapter.isManager(userid, club.id) do
                nil ->
                  {:error, "permit denied"}
                manager ->
                  {:ok, manager}
            end
      end
    end


    def central_control(params) do
      case params.opcode do
        1 ->
          user_create_club(params)
        2->
          allowPartIn(params)
        5 ->
          requestPartin(params)
        7 ->
          show_user_club(params.userid)
        8 ->
          show_user_in_club(params.userid, params.invitecode)
        9 ->
          show_user_unread_msg(params)
        10 ->
          show_msg(params)
        11 ->
          createActivity(params)
        12 ->
          showActivityList(params)
        13 ->
          showActivityDetail(params)
        14 ->
          createFinancial(params)
        15 ->
          showClubFinancialList(params)
        16 ->
          showFinancialDetail(params)
        17 ->
          updateFinancial(params)
        18 ->
          createVote(params)
        19 ->
          showVoteList(params)
        20 ->
          showVoteDetail(params)
        21 ->
          createVoteChoice(params)
        22 ->
          showVoteResult(params)
        23 ->
          show_club_member(params.invitecode)
        _ ->
          {:error,  %{"errormsg" => "其他端口暂不开放"}}
      end
    end
end
